home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / devices and hardware / drivers / traddriverloaderlib / traddriverloaderlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  22.2 KB  |  778 lines

  1. /*
  2.     File:        TradDriverLoaderLib.c
  3.     
  4.     Description:Implementation for the pseudo-DriverLoaderLib for 'DRVR's.
  5.  
  6.     Author:        Quinn "The Eskimo!"
  7.  
  8.     Copyright:     Copyright: © 1996-1999 by Apple Computer, Inc.
  9.                 all rights reserved.
  10.     
  11.     Disclaimer:    You may incorporate this sample code into your applications without
  12.                 restriction, though the sample code has been provided "AS IS" and the
  13.                 responsibility for its operation is 100% yours.  However, what you are
  14.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  15.                 after having made changes. If you're going to re-distribute the source,
  16.                 we require that you make it clear in the source that the code was
  17.                 descended from Apple Sample Code, but that you've made changes.
  18.     
  19.     Change History (most recent first):
  20.                 6/23/99    Updated for Metrowerks Codewarrrior Pro 2.1(KG)
  21.  
  22. */
  23.  
  24. #include <LowMem.h>
  25. #include <DriverGestalt.h>
  26. #include <TextUtils.h>
  27.  
  28. // Switched from using:
  29. //
  30. //   #include <PLStringFuncs.h>
  31. //
  32. // to using BlockMoveData because it's so hard to get PLstrcpy working
  33. // across a zillion different compilers.  *sigh*
  34.  
  35. #include "TradDriverLoaderLib.h"
  36.  
  37. ///////////////////////////////////////////////////////////////////////////
  38.  
  39. extern pascal SInt16 TradHigherDriverVersion(NumVersion *dv1, NumVersion *dv2)
  40. {
  41.     UInt16 nonRelRev1, nonRelRev2;
  42.  
  43.     if (dv1->majorRev           > dv2->majorRev)        return  1;
  44.     if (dv1->majorRev           < dv2->majorRev)        return -1;
  45.     if (dv1->minorAndBugRev     > dv2->minorAndBugRev)  return  1;
  46.     if (dv1->minorAndBugRev     < dv2->minorAndBugRev)  return -1;
  47.     if (dv1->stage              > dv2->stage)           return  1;
  48.     if (dv1->stage              < dv2->stage)           return -1;
  49.  
  50.     nonRelRev1 = dv1->nonRelRev;
  51.     nonRelRev2 = dv2->nonRelRev;
  52.     
  53.     if (dv1->stage == finalStage) {
  54.         if (dv1->nonRelRev == 0)                 nonRelRev1 = 0xFFFF;
  55.         if (dv2->nonRelRev == 0)                 nonRelRev2 = 0xFFFF;
  56.     }
  57.  
  58.     if (nonRelRev1 > nonRelRev2)                        return  1;
  59.     if (nonRelRev1 < nonRelRev2)                        return -1;
  60.  
  61.     return 0;
  62. }
  63.  
  64.  
  65. ///////////////////////////////////////////////////////////////////////////
  66.  
  67. extern pascal UnitNumber TradHighestUnitNumber(void)
  68.     // See comment in header file.
  69. {
  70.     return ( LMGetUnitTableEntryCount() - 1);
  71. }
  72.  
  73. ///////////////////////////////////////////////////////////////////////////
  74.  
  75. extern pascal Boolean TradDriverGestaltIsOn(DriverFlags flags)
  76.     // See comment in header file.
  77. {
  78.     return ( (flags & kmDriverGestaltEnableMask) != 0 );
  79. }
  80.  
  81. ///////////////////////////////////////////////////////////////////////////
  82.  
  83. static OSErr DriverGestaltOnOff(DriverRefNum refNum, Boolean setIt)
  84.     // This routine is called by TradDriverGestaltOn and
  85.     //  TradDriverGestaltOff to either set or clear the
  86.     //  kmDriverGestaltEnableMask bit in the DCE flags.
  87. {
  88.     OSErr err;
  89.     AuxDCEHandle thisDCE;
  90.     
  91.     // First called TradGetDriverInformation to validate the refNum
  92.     //  and verify that the driver exists.
  93.     err = TradGetDriverInformation(refNum, nil, nil, nil, nil);
  94.     if (err == noErr) {
  95.         thisDCE = (AuxDCEHandle) GetDCtlEntry(refNum);
  96.         if (setIt) {
  97.             (**thisDCE).dCtlFlags |= kmDriverGestaltEnableMask;
  98.         } else {
  99.             (**thisDCE).dCtlFlags &= ~kmDriverGestaltEnableMask;
  100.         }
  101.     }
  102.     
  103.     return (err);
  104. }
  105.  
  106. ///////////////////////////////////////////////////////////////////////////
  107.  
  108. extern pascal OSErr TradDriverGestaltOn(DriverRefNum refNum)
  109.     // See comment in header file.
  110. {
  111.     return ( DriverGestaltOnOff(refNum, true) );
  112. }
  113.  
  114. ///////////////////////////////////////////////////////////////////////////
  115.  
  116. extern pascal OSErr TradDriverGestaltOff(DriverRefNum refNum)
  117.     // See comment in header file.
  118. {
  119.     return ( DriverGestaltOnOff(refNum, false) );
  120. }
  121.  
  122. ///////////////////////////////////////////////////////////////////////////
  123.  
  124. extern pascal OSErr TradOpenInstalledDriver(DriverRefNum refNum, SInt8 ioPermission)
  125.     // See comment in header file.
  126. {
  127.     OSErr                 err;
  128.     Str255                driverName;
  129.     DriverRefNum    realRefNum;
  130.  
  131.     // Check parameters.
  132.     err = noErr;
  133.     if (ioPermission != fsRdWrPerm) {
  134.         err = paramErr;
  135.     }
  136.     
  137.     // Get the name of the driver, then simply open it.
  138.     if (err == noErr) {
  139.         err = TradGetDriverInformation(refNum, nil, nil, driverName, nil);
  140.     }
  141.     if (err == noErr) {
  142.         if ( driverName[0] == 0 ) {
  143.             err = paramErr;
  144.         }
  145.     }
  146.     if (err == noErr) {
  147.         err = OpenDriver(driverName, &realRefNum);
  148.     }
  149.     if (err == noErr) {
  150.         if (realRefNum != refNum) {
  151.             err = paramErr;        // My favourite error code -- at some intrinsic level, every error is a paramErr (-;
  152.         }
  153.     }
  154.     
  155.     return (err);
  156. }
  157.  
  158. ///////////////////////////////////////////////////////////////////////////
  159.  
  160. extern pascal OSErr TradLookupDrivers(UnitNumber beginningUnit,
  161.                                         UnitNumber endingUnit,
  162.                                         Boolean emptyUnits,
  163.                                         ItemCount *returnedRefNums, 
  164.                                         DriverRefNum *refNums)
  165.     // See comment in header file.
  166. {
  167.     OSErr err;
  168.     AuxDCEHandle     *unitTable;
  169.     ItemCount         maxRefNums;
  170.     UnitNumber         currentUnit;
  171.     
  172.     // Sanity check the parameters.
  173.     if ( endingUnit > TradHighestUnitNumber() ) {
  174.         endingUnit = TradHighestUnitNumber();
  175.     }
  176.     err = noErr;
  177.     if ( beginningUnit > TradHighestUnitNumber() ) {
  178.         err = badUnitErr;
  179.     }
  180.     if (err == noErr) {
  181.         if (beginningUnit > endingUnit ) {
  182.             err = paramErr;
  183.         }
  184.     }
  185.  
  186.     // Now do the real work...
  187.     if (err == noErr) {
  188.         unitTable = (AuxDCEHandle *) LMGetUTableBase();
  189.  
  190.         maxRefNums = *returnedRefNums;
  191.         
  192.         // Loop through each unit table entry from beginningUnit to endingUnit inclusive.
  193.         *returnedRefNums = 0;
  194.         currentUnit = beginningUnit;
  195.         while ( currentUnit <= endingUnit ) {
  196.  
  197.             // If we've still got space to return a unit...
  198.             if ( *returnedRefNums < maxRefNums ) {
  199.             
  200.                 // and we're interested in this unit...
  201.                 if (    (emptyUnits && unitTable[currentUnit] == nil) ||
  202.                             (!emptyUnits && unitTable[currentUnit] != nil) ) {
  203.                     
  204.                     // then copy the unit out to the caller's array
  205.                     refNums[*returnedRefNums] = ~currentUnit;
  206.                     *returnedRefNums += 1;
  207.                 }
  208.             }
  209.             currentUnit += 1;
  210.         }
  211.     
  212.     }
  213.     
  214.     return (err);
  215. }
  216.  
  217. ///////////////////////////////////////////////////////////////////////////
  218.  
  219. enum {
  220.     kNoUnitNumber = 0xFFFF
  221. };
  222.  
  223. static UnitNumber IsDriverInstalled(ConstStr255Param name, UnitNumber skipThisUnit)
  224.     // Look through the unit table to see if there is a driver with this name
  225.     //  already installed.  Note that you might consider calling OpenDriver
  226.     //  here, but that would be wrong.  OpenDriver has similar semantics, but
  227.     //  if it fails to find a driver in the unit table it will search the
  228.     //  current resource chain looking for a DRVR resource to install.
  229.     //  Given that it's likely our client has a DRVR resource in their
  230.     //  resource chain ('cause they're messing around trying to install
  231.     //  drivers), and that OpenDriver will install it without detaching
  232.     //  it from the client's resource file, and that the client's
  233.     //  resource file may go away (ie they're a DropMounter-like application
  234.     //  or some INIT running at system startup), this would be bad.
  235. {
  236.     UnitNumber    endingUnit;
  237.     UnitNumber    unit;
  238.     Str255            unitName;
  239.     
  240.     endingUnit = TradHighestUnitNumber();
  241.     
  242.     for (unit = 0; unit <= endingUnit; unit++) {
  243.         if ( TradGetDriverInformation(~unit, nil, nil, unitName, nil) == noErr) {
  244.             if ( unit != skipThisUnit && EqualString(name, unitName, false, true) ) {
  245.                 return (unit);
  246.             }
  247.         }
  248.     }
  249.     
  250.     return (kNoUnitNumber);
  251. }
  252.  
  253. ///////////////////////////////////////////////////////////////////////////
  254.  
  255. enum {
  256.     kMaximumNumberOfUnitTableEntries = 128,
  257.     // kMaximumNumberOfUnitTableEntries = 8192,
  258.     
  259.     // kMaximumNumberOfUnitTableEntries is documented in Technote
  260.     //  DV 23 "Driver Education" <http://devworld.apple.com/dev/technotes/dv/dv_23.html>
  261.     //  as being the maximum size that the classic Device Manager
  262.     //  would grow the unit table.  In theory, this limits the system
  263.     //  to 128 unit table entries.  This limit is also enforced by the
  264.     //  PCI DriverLoaderLib.
  265.     // However the traditional Mac OS is capable of dealing with much more
  266.     //  than 128 units.  In fact, some multi-port serial card vendors
  267.     //  regularly install more.  So while I've set this limit to 128,
  268.     //  I have tested TradDriverLoaderLib installing up to 500 device
  269.     //  drivers.  I've also filed a bug against the PCI DriverLoaderLib to
  270.     //  get its limit raised.
  271.     // The alternative maximum I've supplied (8192) is designed to
  272.     //  keep the unit table smaller than 32K.  This is important
  273.     //  because many people use 68K word indexing (ie x(a0,d0.w) to
  274.     //  to access the entries.
  275.     
  276.     kNumberOfEntriesToGrowUnitTable = 4
  277.     
  278.     // Technote DV 23 "Driver Education"
  279.     //  <http://devworld.apple.com/dev/technotes/dv/dv_23.html>
  280.     //  documents that the system grows the unit table by 4 entries
  281.     //  at a time.
  282. };
  283.  
  284. ///////////////////////////////////////////////////////////////////////////
  285.  
  286. static OSErr GrowUnitTable()
  287.     // This routine grows the unit table by kNumberOfEntriesToGrowUnitTable,
  288.     //  up to a maximum of kMaximumNumberOfUnitTableEntries.  The routine
  289.     //  is guaranteed to grow the table by at least one entry, or fail
  290.     //  with an error.
  291. {
  292.     OSErr        err;
  293.     Ptr         oldTable;
  294.     Ptr         newTable;
  295.     UInt32    oldCount;
  296.     UInt32    newCount;
  297.  
  298.     // Get the info about the old table, and calculate the new table size.    
  299.     oldTable = LMGetUTableBase();
  300.     oldCount = LMGetUnitTableEntryCount();
  301.     newCount = oldCount + kNumberOfEntriesToGrowUnitTable;
  302.  
  303.     // Guard against growing the table too big.    
  304.     err = noErr;
  305.     if (newCount > kMaximumNumberOfUnitTableEntries) {
  306.         err = unitTblFullErr;
  307.     }
  308.     
  309.     // Allocate the new unit table in the system heap.  Note that we
  310.     //  clear the newly allocated memory, so that later on, when we
  311.     //  use this memory as the new unit table, the newly allocated
  312.     //  entries will be empty.
  313.  
  314.     if (err == noErr) {
  315.         newTable = NewPtrSysClear( newCount * sizeof(AuxDCEHandle));
  316.         err = MemError();
  317.     }
  318.  
  319.     // Copy the unit table entries over to the new table and then switch
  320.     //  to that table.  Note that this sequence doesn't disable interrupts,
  321.     //  instead it relies on the fact that programs can't modify the
  322.     //  unit table at interrupt time, and thus we, running at non-interrupt
  323.     //  time, have exclusive write access to the table.
  324.  
  325.     // Note that the sequence of these next few lines is *very* important.
  326.     //  If we did this in any other order, you could get to a situation
  327.     //  where interrupt code might be looking at an inconsistent 
  328.     //  unit table, which would be bad.
  329.     
  330.     // The sequence is:
  331.     //  1. copy the old unit table entries to the new table
  332.     //  2. change the unit table base pointer, so that interrupts
  333.     //         start using the new unit table
  334.     //  3. then change the unit table count, so that we have
  335.     //         more entries available
  336.     
  337.     if (err == noErr) {
  338.         BlockMoveData(oldTable, newTable, oldCount * sizeof(AuxDCEHandle));    // 1.
  339.         LMSetUTableBase(newTable);                                                                                    // 2.
  340.         LMSetUnitTableEntryCount(newCount);                                                                    // 3.
  341.         
  342.         // Now its safe to dispose of the old unit table.
  343.         DisposePtr(oldTable);
  344.     }
  345.  
  346.     return (err);    
  347. }
  348.  
  349. ///////////////////////////////////////////////////////////////////////////
  350.  
  351. static OSErr FindFreeUnitNumber(UnitNumber beginningUnit,
  352.                                 UnitNumber endingUnit, 
  353.                                 UnitNumber *foundUnit)
  354.     // This routine walks the unit table looking for a free
  355.     //  slot.  The slot must be between beginningUnit
  356.     //  and endingUnit.  If endingUnit is greater than
  357.     //  TradHighestUnitNumber(), then we're allowed
  358.     //  to grow the unit table to meet our needs.
  359. {
  360.     OSErr err;
  361.     Boolean found;
  362.     UnitNumber currentUnit;
  363.     UnitNumber trueEndingUnit;
  364.     AuxDCEHandle *unitTable;
  365.     
  366.     unitTable = (AuxDCEHandle *) LMGetUTableBase();
  367.     
  368.     // Find trueEndingUnit, which is the minimum
  369.     //  of endingUnit and the highest unit number.
  370.     trueEndingUnit = endingUnit;
  371.     if ( trueEndingUnit > TradHighestUnitNumber() ) {
  372.         trueEndingUnit = TradHighestUnitNumber();
  373.     }
  374.  
  375.     // Scan through the unit table, starting at beginningUnit
  376.     //  and ending at trueEndingUnit, looking for an
  377.     //  empty slot.
  378.     currentUnit = beginningUnit;
  379.     found = false;
  380.     while (currentUnit <= trueEndingUnit && !found) {
  381.         found = (unitTable[currentUnit] == nil);
  382.         if (!found) {
  383.             currentUnit += 1;
  384.         }
  385.     }
  386.  
  387.     // Finish up.    
  388.     if (found) {
  389.         // We found an empty slot, return it.
  390.         *foundUnit = currentUnit;
  391.         err = noErr;
  392.     } else {
  393.  
  394.         // We didn't find an empty slot.  If we're
  395.         //  allowed to, grow the unit table, otherwise
  396.         //  just return an error.
  397.         
  398.         if (endingUnit > trueEndingUnit) {
  399.             err = GrowUnitTable();
  400.             if (err == noErr) {
  401.                 *foundUnit = trueEndingUnit + 1;
  402.             }
  403.         } else {
  404.             err = unitTblFullErr;
  405.         }
  406.     }
  407.     
  408.     return (err);    
  409. }
  410.  
  411. ///////////////////////////////////////////////////////////////////////////
  412.  
  413. extern pascal OSErr TradInstallDriverFromPtr(DRVRHeaderPtr driver,
  414.                                                 UnitNumber beginningUnit,
  415.                                                 UnitNumber endingUnit,
  416.                                                 DriverRefNum *refNum)
  417.     // See comment in header file.
  418. {
  419.     OSErr err;
  420.     UnitNumber foundUnit;
  421.     AuxDCEHandle theDCE;
  422.     
  423.     // Sanity check parameters.
  424.     err = noErr;
  425.     if ( driver == nil ) {
  426.         err = paramErr;
  427.     }
  428.     if ( beginningUnit > TradHighestUnitNumber() ) {
  429.         err = badUnitErr;
  430.     }
  431.     if ( err == noErr && beginningUnit > endingUnit ) {
  432.         err = paramErr;
  433.     }
  434.     
  435.     // Check whether this driver is already installed.
  436.     if ( err == noErr ) {
  437.         // Check whether it's already installed.
  438.         foundUnit = IsDriverInstalled(&driver->drvrName[0], kNoUnitNumber);
  439.         if (foundUnit != kNoUnitNumber) {
  440.             // Return the refnum of the existing driver to the caller.
  441.             *refNum = ~foundUnit;
  442.             err = dupFNErr;
  443.         }
  444.     }
  445.     
  446.     // Now walk the unit table looking for a free slot.
  447.     if (err == noErr) {
  448.         err = FindFreeUnitNumber(beginningUnit, endingUnit, &foundUnit);
  449.     }
  450.  
  451.     // We've got a free slot, so let's install the device driver.
  452.     //  Note that we use DriverInstallReserveMem, rather than the standard
  453.     //  DriverInstall, so that the DCE is allocated low in the system
  454.     //  heap.  DriverInstallReserveMem was introduced with the 128K ROM.
  455.  
  456.     if (err == noErr) {
  457.         err = DriverInstallReserveMem(driver, ~foundUnit);
  458.     }
  459.     
  460.     // Now do some important tidying up.
  461.     if (err == noErr) {
  462.  
  463.         // Return the refNum to the caller.
  464.         *refNum = ~foundUnit;
  465.  
  466.         theDCE = (AuxDCEHandle) GetDCtlEntry(*refNum);
  467.         
  468.         // Now setup the DCE properly.  There's a whole pile of things we
  469.         //  have to do, mainly because DriverInstall is such a brain-dead
  470.         //  routine.
  471.         
  472.         // First up, DriverInstall seems to ignore the first parameter
  473.         //  passed to it, so we have to blat the pointer to the driver code in
  474.         //  yourself afterwards.
  475.         
  476.         (**theDCE).dCtlDriver = (Ptr) driver;
  477.  
  478.         // Then we have to set up the flags.  We do this by copying the flags
  479.         //  out of the first word of the driver code.  We make sure to clear
  480.         //  the dRAMBased bit because we're actually a pointer-based driver
  481.         //  and DriverInstallReserveMem sets it to provisionally indicate that
  482.         //  we're a handle based driver.  We also set dNeedLock because
  483.         //  we want the the Device Manager to lock down the DCE.
  484.         
  485.         (**theDCE).dCtlFlags = (driver->drvrFlags & ~dRAMBasedMask) | dNeedLockMask;
  486.  
  487.         // There's also a bunch of fields we copy straight across without
  488.         //  any modification.  You might expect DriverInstall to copy
  489.         //  across these fields from the driver header to the DCE, but it doesn't
  490.         //  do that, so we do it ourselves.
  491.  
  492.         (**theDCE).dCtlDelay = driver->drvrDelay;
  493.         (**theDCE).dCtlEMask = driver->drvrEMask;
  494.         (**theDCE).dCtlMenu  = driver->drvrMenu;
  495.  
  496.         // Finally, we lock the DCE.
  497.         // Note that strictly speaking we don't need to HLock the DCE
  498.         //  because the Device Manager will do it when it you open a driver
  499.         //  that has dNeedLock set.  However, we want to
  500.         //  lock it now because DriverInstallReserveMem has just made sure
  501.         //  that the DCE was created low in the system heap, so we might as
  502.         //  well lock it down low rather than let it float.
  503.  
  504.         HLock( (Handle) theDCE );
  505.     }
  506.     
  507.     return (err);
  508. }
  509.  
  510. ///////////////////////////////////////////////////////////////////////////
  511.  
  512. extern pascal OSErr TradInstallDriverFromHandle(DRVRHeaderHandle driver,
  513.                                                 UnitNumber beginningUnit,
  514.                                                 UnitNumber endingUnit,
  515.                                                 DriverRefNum *refNum)
  516.     // See comment in header file.
  517. {
  518.     OSErr err;
  519.     Size  driverSize;
  520.     DRVRHeaderPtr driverPtr;
  521.     
  522.     driverPtr = nil;
  523.     
  524.     err = noErr;
  525.     if (driver == nil || *driver == nil) {
  526.         err = paramErr;
  527.     }
  528.     if (err == noErr) {
  529.         driverSize = GetHandleSize( (Handle) driver );
  530.     }
  531.     if (err == noErr) {
  532.         driverPtr = (DRVRHeaderPtr) NewPtrSys( driverSize );
  533.         err = MemError();
  534.     }
  535.     
  536.     if (err == noErr) {
  537.         // This is *not* a BlockMoveData call. This time, we really are moving code!
  538.         //  I could have put cache flushing code in here, but then I would have
  539.         //  had to check whether it was available or not.
  540.         BlockMove( *driver, driverPtr, driverSize );
  541.         
  542.         err = TradInstallDriverFromPtr(driverPtr, beginningUnit, endingUnit, refNum);
  543.     }
  544.     
  545.     // Clean up.
  546.     if (err != noErr) {
  547.         // We're returning an error.  The API says we should leave the handle untouched,
  548.         //  but we should definitely clean up our new copy of the driver code.
  549.         if (driverPtr != nil) {
  550.             DisposePtr( (Ptr) driverPtr );
  551.         }
  552.     }
  553.     
  554.     return (err);
  555. }
  556.  
  557. ///////////////////////////////////////////////////////////////////////////
  558.  
  559. extern pascal OSErr TradInstallDriverFromResource(SInt16 rsrcID, StringPtr rsrcName,
  560.                                                 UnitNumber beginningUnit,
  561.                                                 UnitNumber endingUnit,
  562.                                                 DriverRefNum *refNum)
  563.     // See comment in header file.
  564. {
  565.     OSStatus err;
  566.     Handle driverHandle;
  567.     
  568.     // Note: We don't care which zone the resource gets loaded, because 
  569.     //  TradInstallDriverFromHandle makes a copy of it anyway.
  570.  
  571.     // Get the resource, using either rsrcID or rsrcName.
  572.     if (rsrcName == nil) {
  573.         driverHandle = Get1Resource('DRVR', rsrcID);
  574.     } else {
  575.         driverHandle = Get1NamedResource('DRVR', rsrcName);
  576.     }
  577.     
  578.     // Set err if we couldn't get the resource.
  579.     if (driverHandle == nil) {
  580.         err = ResError();
  581.         if (err == noErr) {
  582.             err = resNotFound;
  583.         }
  584.     } else {
  585.         // Make sure we're not killed by some clown making the 'DRVR' purgeable.
  586.         HNoPurge(driverHandle);                    
  587.         err = MemError();
  588.     }
  589.     
  590.     // Now install the driver as if we'd got it from a memory handle.    
  591.     if (err == noErr) {
  592.         err = TradInstallDriverFromHandle( (DRVRHeaderHandle) driverHandle, beginningUnit, endingUnit, refNum);
  593.  
  594.         ReleaseResource(driverHandle);
  595.         if (err == noErr) {
  596.             err = ResError();
  597.         }
  598.     }
  599.     
  600.     return (err);
  601. }
  602.  
  603. ///////////////////////////////////////////////////////////////////////////
  604.  
  605. extern pascal OSErr TradGetDriverInformation(DriverRefNum refNum,
  606.                                                 UnitNumber *thisUnit,
  607.                                                 DriverFlags *flags,
  608.                                                 StringPtr name,
  609.                                                 DRVRHeaderPtr *driverHeader
  610.                                                 )
  611.     // See comment in header file.
  612. {
  613.     OSErr err;
  614.     UnitNumber             tmpUnit;
  615.     AuxDCEHandle        tmpDCE;
  616.     DRVRHeaderPtr        tmpHeader;
  617.     DRVRHeaderHandle    tmpDriverHandle;
  618.     
  619.     // Get some initial information.
  620.     tmpUnit = ~refNum;
  621.     
  622.     // Sanity check the refNum parameter.
  623.     err = noErr;
  624.     if (tmpUnit > TradHighestUnitNumber()) {
  625.         err = badUnitErr;
  626.     }
  627.     if (err == noErr) {
  628.         tmpDCE = (AuxDCEHandle) GetDCtlEntry(refNum);
  629.         if ( tmpDCE == nil ) {
  630.             err = unitEmptyErr;
  631.         }
  632.     }
  633.     if (err == noErr) {
  634.         if ( (*tmpDCE == nil) || (GetHandleSize( (Handle) tmpDCE) < sizeof(DCtlEntry)) ) {
  635.             err = dceExtErr;
  636.         }
  637.     }
  638.     
  639.     // Get the information from the DCE.
  640.     if (err == noErr) {
  641.  
  642.         // From the DCE, find the DRVR header.  This can fail for a number of reasons:
  643.         //     1. dCtlDriver is nil
  644.         //     2. the driver is handle based, and the handle's master point is nil
  645.         //     3. the driver is handle based, and the driver's handle is too small
  646.         // In all of these cases, we set tmpHeader to nil, returning nil to our
  647.         // client.
  648.         
  649.         tmpHeader = (DRVRHeaderPtr) (**tmpDCE).dCtlDriver;
  650.         if ( tmpHeader != nil ) {
  651.             if ( ((**tmpDCE).dCtlFlags & dRAMBasedMask) != 0 ) {
  652.  
  653.                 tmpDriverHandle = (DRVRHeaderHandle) tmpHeader;
  654.                 
  655.                 if ( (*tmpDriverHandle != nil) &&
  656.                             (GetHandleSize( (Handle) tmpDriverHandle) >= sizeof(DRVRHeader)) ) {
  657.                     tmpHeader = *tmpDriverHandle;
  658.                 }
  659.             }
  660.         }
  661.         
  662.         // Now copy out the various requested parameters
  663.         if (thisUnit != nil) {
  664.             *thisUnit = tmpUnit;
  665.         }
  666.         if (flags != nil) {
  667.             *flags = (**tmpDCE).dCtlFlags;
  668.         }
  669.         if (name != nil) {
  670.             if ( tmpHeader == nil ) {
  671.                 name[0] = 0;
  672.             } else {
  673.                 BlockMoveData(&tmpHeader->drvrName[0], name, tmpHeader->drvrName[0] + 1);
  674.             }
  675.         }
  676.         if (driverHeader != nil) {
  677.             *driverHeader = tmpHeader;
  678.         }
  679.     }
  680.     
  681.     return (err);
  682. }
  683.  
  684. ///////////////////////////////////////////////////////////////////////////
  685.  
  686. extern pascal OSErr TradRemoveDriver(DriverRefNum refNum, Boolean immediate)
  687.     // See comment in header file.
  688. {
  689.     OSErr                 err;
  690.     DriverFlags     flags;
  691.     DRVRHeaderPtr driverHeader;
  692.  
  693.     // Check parameters.
  694.     err = noErr;
  695.     if (immediate) {
  696.         err = paramErr;
  697.     }
  698.  
  699.     // Get information about the driver we're closing.
  700.     if (err == noErr) {
  701.         err = TradGetDriverInformation(refNum, nil, &flags, nil, &driverHeader);
  702.     }
  703.     if (err == noErr) {
  704.         if ( driverHeader == nil ) {
  705.             err = paramErr;
  706.         }
  707.     }
  708.     
  709.     // If the driver is open, close it.
  710.     if (err == noErr) {
  711.         if ( (flags & dOpenedMask) != 0 ) {
  712.             err = CloseDriver(refNum);
  713.         }
  714.     }
  715.     
  716.     // Now call the system to remove the driver from the unit table.  Note that this
  717.     //  works because of a subtlety in DriverRemove.  If the driver being removed
  718.     //  is a RAM-based driver (which our drivers aren't), DriverRemove will call
  719.     //  ReleaseResource on the dCtlDriver.  We don't want this, so we make our drivers
  720.     //  not RAM-based.
  721.     
  722.     if (err == noErr) {
  723.         err = DriverRemove(refNum);
  724.     }
  725.     
  726.     if (err == noErr) {
  727.         // All is cool, so let's dispose of the code.
  728.         DisposePtr( (Ptr) driverHeader);
  729.     }
  730.     
  731.     return (err);
  732. }
  733.  
  734. ///////////////////////////////////////////////////////////////////////////
  735.  
  736. extern pascal OSErr TradRenameDriver(DriverRefNum refNum, ConstStr255Param newDriverName)
  737.     // See *important* comment in header file.
  738. {
  739.     OSErr             err;
  740.     Str255             driverName;
  741.     DRVRHeaderPtr     driverHeader;
  742.     
  743.     err = noErr;
  744.     if ( newDriverName[0] == 0 ) {
  745.         err = paramErr;
  746.     }
  747.     if (err == noErr) {
  748.         // Get information about the driver we're renaming.
  749.         err = TradGetDriverInformation(refNum, nil, nil, driverName, &driverHeader);
  750.     }
  751.     if (err == noErr) {
  752.         if ( driverHeader == nil ) {
  753.             err = paramErr;
  754.         }
  755.     }
  756.     
  757.     // Now check the name lengths.  See comment in implementation for details.
  758.     if (err == noErr) {
  759.         if ( newDriverName[0] > driverName[0] ) {
  760.             err = paramErr;
  761.         }
  762.     }
  763.     
  764.     // Now check whether the new name is already present in the unit table.
  765.     if (err == noErr) {
  766.         if ( IsDriverInstalled(newDriverName, ~refNum) != kNoUnitNumber ) {
  767.             err = dupFNErr;
  768.         }
  769.     }
  770.     
  771.     // Now copy in the new driver name.
  772.     if (err == noErr) {
  773.         BlockMoveData( newDriverName, &driverHeader->drvrName[0], newDriverName[0] + 1 );
  774.     }
  775.     
  776.     return (err);
  777. }
  778.